/*
 *  Copyright 1999-2019 Seata.io Group.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.auditlog.datasource;

import cn.hutool.core.thread.NamedThreadFactory;
import com.auditlog.datasource.table.cache.TableMetaCacheFactory;
import com.auditlog.util.JdbcConstants;
import com.auditlog.util.JdbcUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * The type Data source proxy.
 *
 * @author sharajava
 */
@Data
@Slf4j
public class DataSourceProxy extends AbstractDataSourceProxy {

    private String dbType;
    private String jdbcUrl;
    /**
     * oracle schema
     */
    private String userName;

    private String resourceId;

    private final ScheduledExecutorService tableMetaExecutor = new ScheduledThreadPoolExecutor(1,
            new NamedThreadFactory("auditLog-tableMetaChecker", true));

    public DataSourceProxy(DataSource target) {
        this.target = target;
        init();
        tableMetaExecutor.scheduleAtFixedRate(() -> {
            try (Connection connection = target.getConnection()) {
                TableMetaCacheFactory.getTableMetaCache(DataSourceProxy.this.getDbType())
                        .refresh(connection, DataSourceProxy.this.getResourceId());
            } catch (Exception ignore) {
            }
        }, 0, 60000, TimeUnit.MILLISECONDS);
    }

    private void init() {
        try (Connection connection = this.target.getConnection()) {
            jdbcUrl = connection.getMetaData().getURL();
            this.resourceId = jdbcUrl;
            dbType = JdbcUtils.getDbTypeStr(jdbcUrl);
            if (JdbcConstants.ORACLE_STR.equals(dbType)) {
                userName = connection.getMetaData().getUserName();
                dbType = JdbcConstants.ORACLE_STR;
            } else if (JdbcConstants.MARIADB_STR.equals(dbType)) {
                dbType = JdbcConstants.MYSQL_STR;
            }
        } catch (SQLException ex) {
            throw new IllegalStateException("初始化数据源失败", ex);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        return new ConnectionProxy(this, target.getConnection());
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        Connection connection = this.target.getConnection(username, password);
        return new ConnectionProxy(this, connection);
    }
}
